#pragma once
#include "Astronomy/Coordinate.hpp"
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <tuple>

typedef struct
{
    double D;
    double M;
    double Mp;
    double F;
    double eiA;
    double erA;
} MoonEclipticCoefficient;

class CelestialMoon
{
public:
    /**
     * @brief [M_v] 月球速度计算
     *
     * @param T
     *        儒略世纪数;
     * @return double
     */
    static double Velocity(const double T) noexcept;
    /*
     * @brief [M_Lon_t]计算太阳地心黄道经度;
     *
     * @param T
     *        儒略世纪数;
     *
     * @param CalcItemsCount
     *        参与计算数量 默认：-1 全部参与计算;
     *
     * @return 太阳黄经(单位：度);
     */
    static double EclipticLongitude(const double T, int CalcItemsCount = -1) noexcept;
    /*
     * @brief 计算太阳黄道纬度;
     *
     * @param T
     *        儒略世纪数;
     *
     * @param CalcItemsCount
     *        参与计算数量 默认：-1 全部参与计算;
     *
     * @return 太阳黄纬度(单位：度);
     */
    static double EclipticLatitude(const double T, int CalcItemsCount = -1) noexcept;

    /*
     * @brief 月球光行差修正量-(黄经) 误差0.07";
     *
     * @param T
     *        儒略世纪数;
     *
     *
     * @return 月球黄经的修正参数 Δλ(单位是角秒/日);
     */
    static double VariationEclipticLongitude(double T) noexcept { return -3.4E-6; }
    /*
     * @brief 月球光行差修正量-(纬度) 误差：0.0006 ”;
     *
     * @param T
     *        儒略世纪数;
     *
     *
     * @return 月球黄纬的修正参数 Δλ(单位是角秒/日);
     */
    static double VariationEclipticLatitude(double T) noexcept;

    /*
     * @brief 计算月球半径矢量;
     *
     * @param T
     *        儒略世纪数;
     *
     * @param CalcItemsCount
     *        参与计算数量 默认：-1 全部参与计算;
     *
     * @return 半径矢量(单位：);
     */
    static double RadiusVector(const double T, int CalcItemsCount = -1) noexcept;

    /**
     * @brief 月球被照亮部分的比例;
     *
     * @param T
     *          儒略世纪数力学时
     * @return double 比例;
     */
    static double IlluminatesTheScale(const double T) noexcept;

    /**
     * @brief 计算地球-月球站心视半径(角秒)
     *
     * @param Latitude
                        地平纬度
     * @param CentroidDistance
                        地月质心距离
     * @return double 站心视半径(角秒)
     */
    static double ApparentRadius(const double Latitude, const double CentroidDistance) noexcept;

    /**
     * @brief [moonMinR]计算月球近/远地点距离及时间;
     *
     * @param T
     *          儒略世纪数力学时
     * @param isPerigee
                是否计算近地点[true = 近地点, false = 远地点];
     * @return std::tuple<double = jdt, double = distance>

        apogee  = 远地点
        perigee = 近地点
     */
    static std::tuple<double, double> CalcApogeeOrPerigee(const double T, const bool isPerigee = false) noexcept;

    /**
     * @brief [moonNode] 月亮升交点;
     *
     * @param t
     *        儒略世纪数力学时
     * @param asc
     *         平升(降)交点;
     * @return double
     */
    static std::tuple<double, double> AscendingNode(double t, bool asc) noexcept;
    
    /**
     * @brief [suoN] 返回朔日的编号;
     *
     * @param jd
     *          应在朔日附近，允许误差数天
     * @return double
     */
    constexpr static double NewMoonDay(double jd) { return floor((jd + 8.0) / 29.5306); }

    /**
     * @brief 计算当前月球坐标;
     *
     * @param T
     *           儒略世纪数;
     * @param numberOfL
     *           经度数据参与计算数量;
     * @param numberOfB
     *           纬度数据参与计算数量;
     * @param numberOfR
     *           间距数据参与计算数量;
     * @return Coordinate3D 坐标系统;
     */
    static Coordinate3D Coordinate(double T, int numberOfL, int numberOfB, int numberOfR) noexcept;

    /**
     * @brief [M_Lon_t] 已知真月球黄经求时间
     *
     * @param W
     *        月球真黄经值;
     * @return double
     */
    static double GetEclipticLongitudeTime(double W) noexcept;

private:
    /**
    * @brief 计算周期性项目;
    * 
    * @param T  
    *        儒略世纪数;
    * @param coff 
    *         数据集指针;
    * @param count 
    *         数组大小;
    * @param CalculateItemsCount 
    *         允许参与计算的数据大小（大于0 有效，反之数据集全部数据参与计算）;;
    * @return double 结果;
    */
    static double CalcPeriodicTerm(const double T, const MoonEclipticCoefficient *coff, const size_t count, const size_t CalculateItemsCount = 0) noexcept;

};